home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Plus 2002 #3
/
Amiga Plus CD - 2002 - No. 03.iso
/
AmiSoft
/
Util
/
Cli
/
Howdif.lha
/
howdif
/
source
/
howdif.c
next >
Wrap
C/C++ Source or Header
|
2003-01-30
|
11KB
|
359 lines
/* HowDif 2.02a for Amiga
Quick-and-dirty routine written to compare two files. The assumption is
that they are files known to be different from one another, already. I
want to know HOW different they are from one another. Essentially, this
program reads two files, notes the number of bytes read, and notes
how many bytes do not match. (This is a strict byte-for-byte
comparison.)
Written by James Jacobs and Ward Shrake
Last update: January 31, 2003 */
#include <exec/types.h>
#include <dos/dos.h>
#include <stdlib.h> /* EXIT_SUCCESS, EXIT_FAILURE */
typedef signed char FLAG; /* 8-bit signed quantity (replaces BOOL) */
typedef signed char SBYTE; /* 8-bit signed quantity (replaces Amiga BYTE) */
typedef signed short SWORD; /* 16-bit signed quantity (replaces Amiga WORD) */
typedef signed long SLONG; /* 32-bit signed quantity (same as LONG) */
#define elif else if
#define AGLOBAL ; /* global (project-scope) */
#define MODULE static /* external static (file-scope) */
#define PERSIST static /* internal static (function-scope) */
#define AUTO auto /* automatic (function-scope) */
MODULE STRPTR MemoryPtr[3] = {NULL, NULL};
MODULE struct FileInfoBlock* FIBPtr = NULL;
MODULE struct RDArgs* ArgsPtr = NULL;
MODULE BPTR FileHandle = NULL;
MODULE TEXT output[1024 + 1],
ansi1[20],
ansi2[20];
MODULE FLAG inverted = FALSE,
vanilla = FALSE;
MODULE ULONG size[3];
MODULE void cleanexit(SLONG rc);
MODULE void hexalize(UBYTE data);
MODULE void invert(void);
MODULE void deinvert(void);
int main(int argc, char** argv)
{ AUTO ULONG i, j,
length,
percent1, percent2,
signals,
br,
bw = 0, // number of total mismatches found
bpl = 14; // bytes per line
AUTO FLAG compare = FALSE;
PERSIST TEXT arcadia[] = " /\\abcdefghijklm0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ.,+$nopqrstu";
AUTO STRPTR primary, secondary;
AUTO SLONG args[5] = {0L, 0L, 0L, 0L, 0L};
if (0)
{ strcpy(arcadia, "$VER: HowDif 2.02a for Amiga (31.1.2003)");
}
ansi1[0] = 0x9b;
ansi1[1] = 0;
strcat(ansi1, "0;32;40;>0m"); // means `go white on grey'
ansi2[0] = 0x9b;
ansi2[1] = 0;
strcat(ansi2, "0;39;39;>0m"); // means `go back to vanilla'
Printf("HowDif 2.02a for Amiga\n\n");
if (argc) /* started from CLI */
{ if (!(ArgsPtr = ReadArgs
( "FILE1/A,FILE2,-V=VANILLA/S,-W=WIDE/S",
(LONG *) args,
NULL
)))
{ Printf
( "Usage: %s <file1> [<file2>] [-v|VANILLA] [-w|WIDE]\n",
argv[0]
);
cleanexit(EXIT_FAILURE);
}
if (args[1])
{ compare = TRUE;
}
if (args[2])
{ vanilla = TRUE;
}
if (args[3])
{ bpl = 16;
} }
else
{ // started from Workbench
Printf
( "Usage: %s <file1> [<file2>] [-v|VANILLA] [-w|WIDE]\n",
argv[0]
);
cleanexit(EXIT_FAILURE);
}
for (i = 0; i <= 1; i++)
{ if (i == 0 || compare)
{ if (!(FileHandle = (BPTR) Lock(args[i], ACCESS_READ)))
{ Printf("Can't lock %s!\n", args[i]);
exit(EXIT_FAILURE);
}
if (!(FIBPtr = AllocDosObject(DOS_FIB, NULL)))
{ UnLock(FileHandle);
Printf("Can't allocate DOS object!\n");
exit(EXIT_FAILURE);
}
if (!(Examine(FileHandle, FIBPtr)))
{ FreeDosObject(DOS_FIB, FIBPtr);
UnLock(FileHandle);
Printf("Can't examine %s!\n", args[i]);
}
size[i] = FIBPtr->fib_Size;
FreeDosObject(DOS_FIB, FIBPtr);
FIBPtr = NULL;
UnLock(FileHandle);
FileHandle = NULL;
if (!(MemoryPtr[i] = AllocMem(size[i], NULL)))
{ Printf("Out of memory!\n");
cleanexit(EXIT_FAILURE);
}
if (!(FileHandle = (BPTR) Open(args[i], MODE_OLDFILE)))
{ Printf("Can't open %s for reading!\n", args[i]);
cleanexit(EXIT_FAILURE);
}
if (Read(FileHandle, MemoryPtr[i], size[i]) != size[i])
{ Printf("Can't read from %s!\n", args[i]);
cleanexit(EXIT_FAILURE);
}
Close(FileHandle);
FileHandle = NULL;
} }
if (compare)
{ if (size[0] <= size[1])
{ primary = args[0];
secondary = args[1];
} else
{ primary = args[1];
secondary = args[0];
size[2] = size[0];
size[0] = size[1];
size[1] = size[2];
MemoryPtr[2] = MemoryPtr[0];
MemoryPtr[0] = MemoryPtr[1];
MemoryPtr[1] = MemoryPtr[2];
}
Printf(" Primary file is %s (%ld bytes).\n", primary, size[0]);
Printf("Secondary file is %s (%ld bytes).\n\n", secondary, size[1]);
for (br = 0; br < size[0]; br++) // do this loop as long as the file has not ended
{ if (MemoryPtr[0][br] != MemoryPtr[1][br]) // compare the two single bytes
{ bw++; // add one to the counter showing # of mismatches
} } }
else
{ Printf("File is %s (%ld bytes).\n\n", args[0], size[0]);
}
if (size[0] > 65535)
{ Printf(" ");
}
if (bpl == 14)
{ Printf(" 0011 2233 4455 6677 8899 AABB CCDD 0123456789ABCD 0123456789ABCD\n");
if (size[0] > 65535)
{ Printf(" ");
}
Printf(" ---------------------------------- -------------- --------------\n");
} else
{ // assert(bpl == 16);
Printf(" 0011 2233 4455 6677 8899 AABB CCDD EEFF 0123456789ABCDEF\n");
if (size[0] > 65535)
{ Printf(" ");
}
Printf(" --------------------------------------- ----------------\n");
}
for (i = 0; i < size[0]; i += bpl)
{ output[0] = 0;
deinvert();
strcat(output, "$");
if (size[0] > 65535)
{ hexalize(i / 16777216); // do 1st byte
j = i % 16777216; // remove 1st byte
hexalize(j / 65536); // do 2nd byte
j %= 65536; // remove 2nd byte
} else
{ j = i;
}
hexalize(j / 256); // do 3rd byte
hexalize(j % 256); // do 4th byte
strcat(output, ": ");
for (j = 0; j < bpl; j++)
{ if (size[0] > i + j)
{ if (compare)
{ if (MemoryPtr[0][i + j] != MemoryPtr[1][i + j])
{ deinvert();
} else
{ invert();
} }
hexalize(MemoryPtr[0][i + j]);
} else
{ deinvert();
strcat(output, "##");
}
if (j % 2)
{ deinvert();
strcat(output, " ");
} }
if (bpl < 16)
{ for (j = 0; j < bpl; j++)
{ if (size[0] > i + j)
{ if (compare)
{ if (MemoryPtr[0][i + j] != MemoryPtr[1][i + j])
{ deinvert();
} else
{ invert();
} }
if
( MemoryPtr[0][i + j] < ' '
|| (MemoryPtr[0][i + j] >= 0x80 && MemoryPtr[0][i + j] <= 0x9F)
) // if an unprintable character
{ strcat(output, ".");
} else
{ length = strlen(output);
output[length] = MemoryPtr[0][i + j];
output[length + 1] = 0;
} }
else
{ deinvert();
strcat(output, "#");
} }
deinvert();
strcat(output, " ");
}
for (j = 0; j < bpl; j++)
{ if (size[0] > i + j)
{ if (compare)
{ if (MemoryPtr[0][i + j] != MemoryPtr[1][i + j])
{ deinvert();
} else
{ invert();
} }
length = strlen(output);
output[length] = arcadia[MemoryPtr[0][i + j] % 64];
output[length + 1] = 0;
} else
{ deinvert();
strcat(output, "#");
} }
deinvert();
Printf("%s\n", output);
/* From RKM Libraries, p. 432:
get current state of signals */
signals = SetSignal(0L, 0L);
// check for Ctrl-C
if (signals & SIGBREAKF_CTRL_C)
{ // then clear the Ctrl-C signal
SetSignal(0L, SIGBREAKF_CTRL_C);
Printf("User break!\n");
cleanexit(EXIT_SUCCESS);
} }
// when the program is all done comparing, print a summary report onscreen
Printf("\nTotal bytes read: %ld\n", size[0]);
if (compare)
{ Printf("Mismatches found: %ld\n", bw);
/* calculate percentage:
percent1 is the percentage magnified 1 million times.
eg. 1 million = 1%, 100 million = 100%, 56,723,432 = 56.723432%.
By scaling in this way we preserve precision whilst avoiding
the need for true floating point mathematics.
percent2 is the actual integer percentage. */
if (!bw)
{ percent2 = 0;
} else
{ percent1 = (100000000L / size[0]) * bw;
percent2 = percent1 / 1000000L;
}
Printf("Difference: %ld%%\n", percent2);
}
cleanexit(EXIT_SUCCESS); // end of the program. go back to DOS
}
MODULE void invert(void)
{ if (!inverted)
{ if (!vanilla)
{ strcat(output, ansi1);
}
inverted = TRUE;
} }
MODULE void deinvert(void)
{ if (inverted)
{ if (!vanilla)
{ strcat(output, ansi2);
}
inverted = FALSE;
} }
MODULE void cleanexit(SLONG rc)
{ if (FIBPtr)
{ FreeDosObject(DOS_FIB, FIBPtr);
}
if (FileHandle)
{ Close(FileHandle);
}
if (MemoryPtr[0])
{ FreeMem(MemoryPtr[0], size[0]);
}
if (MemoryPtr[1])
{ FreeMem(MemoryPtr[1], size[1]);
}
if (ArgsPtr)
{ FreeArgs(ArgsPtr);
}
exit(EXIT_SUCCESS);
}
MODULE void hexalize(UBYTE data)
{ TEXT tempstring[3];
// Converts an unsigned byte into a hexadecimal string
// do the high byte
if (data / 16 >= 10)
{ tempstring[0] = (data / 16) - 10 + 'A'; // must be done in this order to prevent overflow during calculation of the value
} else
{ tempstring[0] = (data / 16) + '0';
}
// now the low byte
if (data % 16 >= 10)
{ tempstring[1] = (data % 16) - 10 + 'A';
} else
{ tempstring[1] = (data % 16) + '0';
}
tempstring[2] = 0;
strcat(output, tempstring);
}